// Original code by: Daniel Strigl
// No license was attached to the original code.
// Modifications made by: Robert Tenney.
// No licence for this class is provided.

using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Threading;
using System.Security;

namespace RTenney.Utility.Timekeeping
{
    /// <summary>
    /// A high precision timer that uses unmanaged code to retrieve timer information. The precision
    /// is determined by the machine's capability, but can go as far as nanosecond precision.
    /// </summary>
    public class HighPrecisionTimer
    {
        [DllImport("Kernel32.dll"),SuppressUnmanagedCodeSecurity]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool QueryPerformanceCounter(
            out long lpPerformanceCount);

        [DllImport("Kernel32.dll"),SuppressUnmanagedCodeSecurity]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool QueryPerformanceFrequency(
            out long lpFrequency);

        private long startTime, stopTime;
        private long freq;
        
        private long pauseBegin, pauseEnd;
        private bool paused;
        private long pauseDuration;

        /// <summary>
        /// Constructor for the High Precision Timer.
        /// </summary>
        public HighPrecisionTimer()
        {
            if (QueryPerformanceFrequency(out freq) == false)
            {
                // high-performance counter not supported
                throw new Win32Exception();
            }
            pauseDuration = 0;
        }

        /// <summary>
        /// Start the timer.
        /// </summary>
        public void Start()
        {
            // lets do the waiting threads there work
            Thread.Sleep(0);
            QueryPerformanceCounter(out startTime);
        }
        
        /// <summary>
        /// Frequency used by this computer.
        /// </summary>
        public long Frequency{
            get{
                return freq;
            }
        }
        
        /// <summary>
        /// Pauses the timer if active, resumes timer if paused.
        /// </summary>
        public void Pause_Resume(){
            if (paused) {
                QueryPerformanceCounter(out pauseEnd);
                paused = false;
                pauseDuration += (pauseEnd - pauseBegin);
            } else{
                QueryPerformanceCounter(out pauseBegin);
                paused = true;
            }
        }
        
        
        /// <summary>
        /// Gets whether this machine is able to do high precision timing or not.
        /// </summary>
        public bool IsHighPrecision{
            get{
                return System.Diagnostics.Stopwatch.IsHighResolution;
            }
        }

        /// <summary>
        /// Stop the timer.
        /// </summary>
        public void Stop()
        {
            QueryPerformanceCounter(out stopTime);
        }

        /// <summary>
        /// Returns the duration of the timer from Start to Stop, in seconds.
        /// </summary>
        public double Duration
        {
            get
            {
                return ((double)(stopTime - startTime) - (double)(pauseDuration)) / (double) freq;
            }
        }
    }
}
